package jrobutt.room.level;

import jrobutt.*;
import jrobutt.room.ExplosionParticleEmitter;
import jrobutt.room.FpsCounter;
import jrobutt.room.menu.titlescreen.TitleScreenRoom;
import jrobutt.room.menu.levelselection.LevelSelectionRoom;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.geom.*;
import javax.swing.*;
import java.util.*;
import java.util.List;

public class LevelRoom extends GameRoom
{
    int level;
    
    float respawn_duration;
    
    TerrainGrid terrain;
    ExplosionParticleEmitter exploder;
    Guy player;
    GuyInputMover player_controller;
    InitialGuyMover player_starter;
    OilGrid oil_grid;
    FinalGuyHandler finalizer;
    GuyCollisionHandler collision_handler;
    GuyCamera camera;
    List<Enemy> enemies;
    float respawn_timer;
    
    ArrayList<KeyboardResponder> cached_keyboard_responders;
    ArrayList<Updatable> cached_updatables;
    ArrayList<Renderable> cached_renderables;
    
    protected Collection<? extends KeyboardResponder> getKeyboardResponders ()
    {
        return cached_keyboard_responders;
    }
    protected Collection<? extends Updatable> getUpdatables ()
    {
        return cached_updatables;
    }
    protected Collection<? extends Renderable> getRenderables ()
    {
        return cached_renderables;
    }
    
    public LevelRoom (int level)
    {
        this.level = level;
        
        cached_keyboard_responders = new ArrayList<KeyboardResponder>(1);
        cached_updatables = new ArrayList<Updatable>(5);
        cached_renderables = new ArrayList<Renderable>(5);
        
        respawn_duration = 30.0f;
    }
    
    private void add_game_object (GameObject obj)
    {
        cached_updatables.add(obj);
        cached_renderables.add(obj);
    }
    
    public Color get_bg_color ()
    {
        return Settings.bgcolor;
    }
    
    public void enter ()
    {
        respawn_timer = -1.0f;
        
        init_level_objects();
        
        // input
        cached_keyboard_responders.add(player_controller);
        
        // real stuff
        cached_renderables.add(camera);
        
        cached_updatables.add(player_starter);
        cached_renderables.add(oil_grid);
        add_game_object(terrain);
        add_game_object(player);
        for (Enemy enemy : enemies) add_game_object(enemy);
        cached_updatables.add(collision_handler);
        cached_updatables.add(finalizer);
        cached_updatables.add(oil_grid);
        cached_renderables.add(player_starter);
        
        cached_updatables.add(exploder);
        cached_renderables.add(exploder);
        
        FpsCounter fps_counter = new FpsCounter();
        cached_updatables.add(fps_counter);
        cached_renderables.add(fps_counter);
    }
    private void init_level_objects ()
    {
        LevelData data = Global.level_data_loader.load("levels/" + level + ".lev");
        
        // terrain
        float t_scale = 16.0f;
        terrain = new TerrainGrid(data, t_scale);
        
        // particle emitter
        GameSprite particle_sprite = new GameSprite(Global.image_loader.load("player_debris.png"), 0.5f, 0.5f);
        exploder = new ExplosionParticleEmitter(particle_sprite);
        
        // player
        Vector2 f = new Vector2(data.player_x, data.player_y); // final position
        f.scale(t_scale);
        Vector2 d = new Vector2(data.player_dir_x, data.player_dir_y); // facing direction
        float length = 3 * Settings.fps * Guy.DEFAULT_MOVE_SPD; // 3 seconds * frames/second * px/frame (speed)
        //                                                         = total distance between initial and final position
        Vector2 p = new Vector2(f.x - d.x*length, f.y - d.y*length); // initial position
        
        GameSprite player_normal_sprite = new GameSprite(Global.image_loader.load("player.png"), 0.5f, 0.5f);
        GameSprite player_dead_sprite = new GameSprite(Global.image_loader.load("player_dead.png"), 0.5f, 0.5f);
        player = new Guy(p.x, p.y, d, player_normal_sprite, player_dead_sprite, exploder);
        player_controller = new GuyInputMover(player);
        
        GameSprite sprite_3 = new GameSprite(Global.image_loader.load("countdown/3.png"), 0.5f, 0.5f);
        GameSprite sprite_2 = new GameSprite(Global.image_loader.load("countdown/2.png"), 0.5f, 0.5f);
        GameSprite sprite_1 = new GameSprite(Global.image_loader.load("countdown/1.png"), 0.5f, 0.5f);
        GameSprite sprite_linger = new GameSprite(Global.image_loader.load("countdown/go.png"), 0.5f, 0.5f);
        
        float sprite_x = Settings.width / 2.0f;
        float sprite_y = Settings.height / 2.0f;
        player_starter = new InitialGuyMover(player, f, terrain, sprite_3, sprite_2, sprite_1, sprite_linger, sprite_x, sprite_y);
        
        // enemies
        enemies = new LinkedList<Enemy>();
        GameSprite enemy_sprite = new GameSprite(Global.image_loader.load("enemy.png"), 0.5f, 0.5f);
        GameSprite laser_sprite = new GameSprite(Global.image_loader.load("laser.png"), 4, 4);
        for (Point enemy_grid_point : data.enemies)
        {
            float enemy_x = (enemy_grid_point.x + 0.5f) * t_scale;
            float enemy_y = (enemy_grid_point.y + 0.5f) * t_scale;
            Vector2 enemy_facing_direction = new Vector2(Vector2.UNIT_X);
            Enemy enemy = new Enemy(enemy_x, enemy_y, enemy_facing_direction, enemy_sprite, laser_sprite);
            enemies.add(enemy);
        }
        
        // oil rect grid
        oil_grid = new OilGrid(4, player);
        
        // finalizer
        finalizer = new FinalGuyHandler(player, new Vector2(data.final_dir_x, data.final_dir_y), terrain, oil_grid);
        
        // collision handler
        collision_handler = new GuyCollisionHandler(player, terrain, finalizer);
        
        // camera
        camera = new GuyCamera(new Dimension(Settings.width, Settings.height), player, terrain);
    }
    public void exit ()
    {
        cached_keyboard_responders.clear();
        cached_updatables.clear();
        cached_renderables.clear();
    }
    
    public GameRoom key_pressed (int key)
    {
        if (key == KeyEvent.VK_ESCAPE)
        {
            return new LevelSelectionRoom();
        }
        return super.key_pressed(key);
    }
    
    public GameRoom update ()
    {
        if (respawn_timer > 0.0f)
        {
            respawn_timer -= 1.0f;
            if (respawn_timer <= 0.0f)
            {
                return this;
            }
        }
        
        super.update();
        
        if (respawn_timer < 0.0f && player.is_dead) // if respawn_timer is inactive
        {
            respawn_timer = respawn_duration; // start the respawn_timer
        }
        if (finalizer.goto_next_room)
        {
            int next_level = level+1;
            if (next_level >= Global.num_levels)
            {
                return new TitleScreenRoom();
            }
            else
            {
                Global.current_level = Math.max(Global.current_level, next_level);
                return new LevelRoom(next_level);
            }
        }
        
        return null;
    }
}
